package com.wtf.dsp.admin.aspect;


import cn.hutool.core.exceptions.ExceptionUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import com.wtf.dsp.admin.core.executor.WtfDynamicDataSourceMybatisConfigExecutor;
import com.wtf.dsp.admin.entity.WtfDspSqlLog;
import com.wtf.dsp.admin.enums.CommonErrorEnum;
import com.wtf.dsp.admin.exception.WtfDspException;
import com.wtf.dsp.admin.filter.LogMdcFilter;
import com.wtf.dsp.admin.mapper.WtfDspSqlLogMapper;
import com.wtf.dsp.admin.model.dto.DsSqlDTO;
import com.wtf.dsp.admin.service.SqlService;
import com.wtf.dsp.admin.util.MdcUtil;
import com.wtf.dsp.core.constant.NsConstant;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jca.cci.CannotGetCciConnectionException;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Date;
import java.util.Optional;

/**
 * description: SQL切面
 * date: 2022/6/18 10:59
 * @author linhuanyou
 * @email 496558736@qq.com
 * @version 1.0
 */
@Aspect
@Slf4j
@Component
public class DynamicDataSourceContextAspect {

    @Autowired
    private WtfDynamicDataSourceMybatisConfigExecutor wtfDynamicDataSourceMybatisConfigExecutor;

    @Resource
    private SqlService sqlService;

    /**
     * 配置切入点表达式
     */
    @Pointcut("@annotation(com.wtf.dsp.admin.annotation.SqlExec)")
    public void dynamicDataSourceSqlExecutePointCut() {
    }

    /**
     * 配置环绕通知
     *
     * @param point point
     * @return object
     */
    @Around("dynamicDataSourceSqlExecutePointCut()")
    public Object dynamicDataSourceSqlExecuteHandle(ProceedingJoinPoint point) throws Throwable {
        Optional<Object> optional = Arrays.stream(point.getArgs()).filter(e -> {
            return e instanceof DsSqlDTO;
        }).findFirst();
        if(!optional.isPresent()){
            throw new WtfDspException(CommonErrorEnum.ERROR_BAS_REQUEST);
        }
        DsSqlDTO dsSqlDTO = validateParams((DsSqlDTO) optional.get());
        boolean requestSuccess = false;
        Exception er = null;
        Object result = null;
        long beginTime = System.currentTimeMillis();
        try {
            DynamicDataSourceContextHolder.push(NsConstant.nsGroupDs(dsSqlDTO.getNs(),dsSqlDTO.getDs()));
            result = point.proceed(point.getArgs());
            requestSuccess = true;
        } catch (Exception e){
            if(e instanceof CannotGetCciConnectionException){
                log.warn("Try to Reload Datasouce Ns: {} Ds :{}",dsSqlDTO.getNs(),dsSqlDTO.getDs());
                try{
                    wtfDynamicDataSourceMybatisConfigExecutor.reLoadDynamicDataSource(dsSqlDTO.getNs(),dsSqlDTO.getDs());
                } catch (Exception e1){
                    log.warn("Try to Reload Datasouce Failed",e);
                }
            }
            er = e;
            throw e;
        } finally {
            DynamicDataSourceContextHolder.poll();
            sqlService.saveSqlLog(MdcUtil.getLogMid(),dsSqlDTO,requestSuccess,result,er,beginTime, System.currentTimeMillis());
        }
        return result;
    }

    private DsSqlDTO validateParams(DsSqlDTO dsSqlDTO) {
        //检验参数
        return dsSqlDTO;
    }

}
